#pragma once

#include <iostream>
#include <string>
#include <pthread.h>
#include <fstream>
#include <vector>
#include <sstream>
#include <sys/types.h>
#include <sys/socket.h>
#include <unordered_map>
#include "Socket.hpp"
#include "log.hpp"

const std::string wwwroot="./wwwroot"; // web 根目录
const std::string sep = "\r\n";
const std::string homepage = "index.html";

class HttpServer;

class HttpRequest
{
public:
    void Deserialize(std::string req)
    {
        while(true)
        {
            size_t pos=req.find(sep);
            if(pos==std::string::npos) break;
            std::string tmp=req.substr(0,pos);
            if(tmp.empty()) break;
            req_header.push_back(tmp);
            req.erase(0,pos+sep.size());
        }
        text=req;
    }
    void Parse()
    {
        std::stringstream ss(req_header[0]);
        ss>>method>>url>>http_version;
        file_path=wwwroot;//  ./wwwroot

        if(url=="/"||url=="/index.html")
        {
            file_path+="/";
            file_path+=homepage;
        }
        else file_path+=url;


    }
    void DebugPrint()
    {
        for(auto &line : req_header)
        {
            std::cout << "--------------------------------" << std::endl;
            std::cout << line << "\n\n";
        }

        std::cout << "method: " << method << std::endl;
        std::cout << "url: " << url << std::endl;
        std::cout << "http_version: " << http_version << std::endl;
        std::cout << "file_path: " << file_path << std::endl;
        std::cout << text << std::endl;
    }

public:
    std::vector<std::string> req_header;
    std::string text;

    // 解析之后的结果
    std::string method;
    std::string url;
    std::string http_version;
    std::string file_path; // ./wwwroot/a/b/c.html 2.png
};


class ThreadData
{
public:
    ThreadData(int fd, HttpServer *s) : sockfd(fd), svr(s)
    {
    }

public:
    int sockfd;
    HttpServer *svr;
};


class HttpServer
{
public:
    HttpServer(const uint16_t &port) : port_(port)
    {
    }
    void Start()
    {
        listensock_.Socket();
        listensock_.Bind(port_);
        listensock_.Listen();

        while(true)
        {
            std::string clientip;
            uint16_t clientport;
            int sockfd=listensock_.Accept(&clientport,&clientip);
            if(sockfd<0) continue;

            log(Info,"Get a new accept,sockfd: %d",sockfd);
            pthread_t pid;
            ThreadData* td=new ThreadData(sockfd,this);
            pthread_create(&pid,nullptr,ThreadRun,td);

        }
    }
    static std::string ReadHtmlContent(const std::string &htmlpath)
    {
        // 坑
        std::ifstream in(htmlpath);
        if(!in.is_open()) return "";
        std::string content;
        std::string line;
        while(std::getline(in, line))
        {
           content += line;
        }

        in.close();

        return content;
    }
    void HandlerHttp(int sockfd)
    {
        char buff[1024];
        int n=recv(sockfd,buff,sizeof(buff),0);
        if(n>0)
        {
            buff[n]=0;
            std::cout<<buff<<std::endl; // 假设我们读取到的就是一个完整的，独立的http 请求
            HttpRequest hreq;
            hreq.Deserialize(buff);
            hreq.Parse();
            hreq.DebugPrint();


            //返回响应
            // std::string text="hello";
            std::string text=ReadHtmlContent(hreq.file_path);
            std::string response_line="HTTP/1.0 200 OK\r\n";
            std::string response_head="Content-Length: ";
            response_head+=std::to_string(text.size());
            std::string blank_line = "\r\n";

            std::string response=response_line;
            response+=response_head;
            response+=sep;
            response+=blank_line;
            response+=text;
            send(sockfd,response.c_str(),response.size(),0);
        }
        close(sockfd);
    }
    static void* ThreadRun(void* args)
    {
        pthread_detach(pthread_self());
        ThreadData* td=static_cast<ThreadData*>(args);
        int sockfd=td->sockfd;
        td->svr->HandlerHttp(td->sockfd);
        delete td;
        return nullptr;
    }
    ~HttpServer()
    {
    }

private:
    Sock listensock_;
    uint16_t port_;
};